package com.qlogic.commons.platform.impls.lucene.indexer.qlor;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.qlogic.commons.StandardLogger;
import com.qlogic.commons.exceptions.BaseException;
import com.qlogic.commons.kernel.Kernel;
import com.qlogic.commons.platform.Service;
import com.qlogic.commons.platform.impls.lucene.indexer.ContentRegistry;
import com.qlogic.commons.platform.impls.lucene.model.DocumentWrapper;
import com.qlogic.commons.platform.impls.lucene.model.FieldWrapper;
import com.qlogic.commons.platform.impls.lucene.model.RegistryRegion;

public class DatabaseContentRegistry extends StandardLogger implements ContentRegistry {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 9093246848454292231L;
	
	public static final String QUERY_REGION_BY_INDEXER_AND_ACTION = "dms.regionByIndexerAndAction";
	public static final String QUERY_ALL_REGION = "dms.allRegions";
	
	private Map regions;
	private Service executablePersistenceLayer;
	
	public Iterator getRegionNames () throws BaseException {
		executablePersistenceLayer = Kernel.getService ("dal2Service/persistence");
		executablePersistenceLayer.call ("newTrx");
		List regionsList = (List)executablePersistenceLayer.call ("list", QUERY_ALL_REGION);
		if (regionsList == null) {
			return null;
		}
		regions = new HashMap (); 
		for (int i = 0; i < regionsList.size (); i++) {
			IndexedRegion region = (IndexedRegion)regionsList.get(i);
			regions.put (region.getIndexer() + region.getAction (), region);
		}
		return regions.keySet().iterator ();
	}
	
	public RegistryRegion getRegion (String regionName) throws BaseException {
		return (RegistryRegion)regions.get (regionName);
	}
	
	private RegistryRegion getRegion (String indexer, int action, Service pLayer) {
		try {
			pLayer.call ("bind", new Object [] {"indexer", indexer});
			pLayer.call ("bind", new Object [] {"action", String.valueOf(action)});
			RegistryRegion registryRegion = 
				(RegistryRegion)pLayer.call ("first", QUERY_REGION_BY_INDEXER_AND_ACTION);
			if (registryRegion == null) {
				registryRegion = (RegistryRegion)pLayer.call ("newObject", IndexedRegion.class);
				registryRegion.setAction (action);
				registryRegion.setIndexer (indexer);
				pLayer.call ("makePersistent", registryRegion);
				pLayer.call ("commitPhysical", new Boolean (false));
			}
			return registryRegion;
		} catch (Throwable th) {
			throw new RuntimeException (th);
		}
	}
	
	private IndexedDocument createIndexedDocument (Service pLayer, DocumentWrapper documentWrapper) throws BaseException {
		IndexedDocument iDoc = (IndexedDocument)pLayer.call ("newObject", IndexedDocument.class);
		iDoc.setDependsOn (documentWrapper.getDependsOn ());
		iDoc.setFieldName (documentWrapper.getFieldName());
		iDoc.setFieldValue (documentWrapper.getFieldValue());
		iDoc.setId (documentWrapper.getId ());
		Map fields = documentWrapper.getFields();
		if (fields != null) {
			Iterator keys = fields.keySet ().iterator ();
			while (keys.hasNext ()) {
				Object key = keys.next ();
				iDoc.getFields().put (key, createIndexedField (pLayer, (FieldWrapper)fields.get (key)));
			}
		}
		pLayer.call ("makePersistent", iDoc);
		return iDoc;
	}
	
	private IndexedField createIndexedField (Service pLayer, FieldWrapper fieldWrapper) throws BaseException {
		IndexedField iField = (IndexedField)pLayer.call ("newObject", IndexedField.class);
		iField.setEncoding (fieldWrapper.getEncoding ());
		iField.setHandler (fieldWrapper.getHandler ());
		iField.setName (fieldWrapper.getName ());
		iField.setStore (fieldWrapper.isStore ());
		iField.setTokenized (fieldWrapper.isTokenized());
		iField.setValue (fieldWrapper.getValue ());
		return iField;
	}
	
	public void registerForAdd(DocumentWrapper documentWrapper, String indexer) throws BaseException {
		Service pLayer = null;
		try {
			pLayer = Kernel.getService ("dal2Service/persistence");
			pLayer.call ("newTrx");
			RegistryRegion registryRegion = getRegion (indexer, ADD, pLayer);
			registryRegion.getDocuments().add(createIndexedDocument (pLayer, documentWrapper));
			pLayer.call ("commit");
		} catch (BaseException be) {
			throw be;
		} finally {
			if (pLayer != null) {
				pLayer.call ("release");
			}
		}
	}

	public void registerForAdd(Map documentWrappers, String indexer) throws BaseException {
		Service pLayer = null;
		try {
			pLayer = Kernel.getService ("dal2Service/persistence");
			pLayer.call ("newTrx");
			RegistryRegion registryRegion = getRegion (indexer, ADD, pLayer);
			Collection docs = documentWrappers.values ();
			Iterator docsIter = docs.iterator ();
			while (docsIter.hasNext ()) {
				registryRegion.getDocuments().add(createIndexedDocument (pLayer, (DocumentWrapper)docsIter.next ()));
			}
			pLayer.call ("commit");
		} catch (BaseException be) {
			throw be;
		} finally {
			if (pLayer != null) {
				pLayer.call ("release");
			}
		}
	}

	public void registerForDelete(String contentId, String indexer) throws BaseException {
		Service pLayer = null;
		try {
			pLayer = Kernel.getService ("dal2Service/persistence");
			pLayer.call ("newTrx");
			RegistryRegion registryRegion = getRegion (indexer, DELETE, pLayer);
			IndexedDocument iDoc = (IndexedDocument)pLayer.call ("newObject", IndexedDocument.class);
			iDoc.setId (contentId);
			pLayer.call ("makePersistent", iDoc);
			registryRegion.getDocuments ().add (iDoc);
			pLayer.call ("commit");
		} catch (BaseException be) {
			throw be;
		} finally {
			if (pLayer != null) {
				pLayer.call ("release");
			}
		}
	}

	public void registerForDelete(String fieldName, String fieldValue, String indexer) throws BaseException {
		Service pLayer = null;
		try {
			pLayer = Kernel.getService ("dal2Service/persistence");
			pLayer.call ("newTrx");
			RegistryRegion registryRegion = getRegion (indexer, DELETE, pLayer);
			IndexedDocument iDoc = (IndexedDocument)pLayer.call ("newObject", IndexedDocument.class);
			iDoc.setFieldName (fieldName);
			iDoc.setFieldValue (fieldValue);
			pLayer.call ("makePersistent", iDoc);
			registryRegion.getDocuments ().add (iDoc);
			pLayer.call ("commit");
		} catch (BaseException be) {
			throw be;
		} finally {
			if (pLayer != null) {
				pLayer.call ("release");
			}
		}
	}

	public void registerForUpdate(DocumentWrapper documentWrapper, String indexer) throws BaseException {
		Service pLayer = null;
		try {
			pLayer = Kernel.getService ("dal2Service/persistence");
			pLayer.call ("newTrx");
			
			IndexedDocument delDoc = (IndexedDocument)pLayer.call ("newObject", IndexedDocument.class);
			delDoc.setId (documentWrapper.getId ());
			delDoc.setDependsOn (indexer + DELETE);
			pLayer.call ("makePersistent", delDoc);
			RegistryRegion deleteRegion = getRegion (indexer, DELETE, pLayer);
			deleteRegion.getDocuments ().add (delDoc);
			
			RegistryRegion addRegion = getRegion (indexer, ADD, pLayer);
			addRegion.getDocuments ().add (createIndexedDocument (pLayer, documentWrapper));
			pLayer.call ("commit");
		} catch (BaseException be) {
			throw be;
		} finally {
			if (pLayer != null) {
				pLayer.call ("release");
			}
		}
	}

	public String getLoggerName() {
		return "Default Content Registry";
	}

	public void setLoggerName(String arg0) {
	}

	public void unregister(RegistryRegion region, DocumentWrapper documentWrapper) throws BaseException {
		console ("Unregister document " + region.getIndexer () + "." + region.getAction () + "/" + documentWrapper.getId ());
		IndexedDocument indexedDocument = (IndexedDocument)documentWrapper;
		indexedDocument.setThreads (indexedDocument.getThreads () + 1);
		if (indexedDocument.getThreads () > 1) {
			Map fields = indexedDocument.getFields();
			if (fields != null && !fields.isEmpty ()) {
				Iterator keys = fields.keySet().iterator ();
				while (keys.hasNext ()) {
					IndexedField field = (IndexedField)fields.get(keys.next ());
					console ("Unregister Field " + field.getName ());
					executablePersistenceLayer.call ("delete", field);
				}
			}
			executablePersistenceLayer.call ("delete", indexedDocument);
		}
	}

	public void flush () throws BaseException {
		try {
			if (executablePersistenceLayer != null) {
				executablePersistenceLayer.call ("printRegisteredObjects");
				executablePersistenceLayer.call ("commit");
			}
		} catch (BaseException ex) {
			ex.printStackTrace ();
		} finally {
			executablePersistenceLayer.call ("release");
		}
	}
	
}
